using Microsoft.AspNetCore.Mvc;
using RuoVea.WeighIns.Server.Language;

namespace RuoVea.WeighIns.Server.Service;

/// <summary>
/// 体重统计与可视化服务
/// </summary>
[ApiExplorerSettings(GroupName = "WeighStatistics")]
public class WeighStatisticsService : IApplicationService
{
    private readonly SugarRepository<InsWeighInfo> _weighInfoRepository;
    private readonly SugarRepository<InsBodyMetrics> _bodyMetricsRepository;
    private readonly ICurrentUser _currentUser;

    public WeighStatisticsService(
        SugarRepository<InsWeighInfo> weighInfoRepository,
        SugarRepository<InsBodyMetrics> bodyMetricsRepository,
        ICurrentUser currentUser)
    {
        _weighInfoRepository = weighInfoRepository;
        _bodyMetricsRepository = bodyMetricsRepository;
        _currentUser = currentUser;
    }

    /// <summary>
    /// 获取体重趋势数据（支持时间范围和时段筛选）
    /// </summary>
    /// <param name="days">查询天数</param>
    /// <param name="meridiemFilter">时段筛选（可选）</param>
    /// <returns></returns>
    public async Task<RestfulResult<List<EnhancedWeightTrendPoint>>> GetEnhancedWeightTrendAsync(
        int days = 30,
        int? meridiemFilter = null)
    {
        var restful = new RestfulResult<List<EnhancedWeightTrendPoint>>();
        var startDate = DateTime.Now.AddDays(-days);

        // 构建查询
        var query = _weighInfoRepository.AsQueryable()
            .Where(u => u.Creator == _currentUser.UserId && u.WeighTime >= startDate);

        // 添加时段筛选
        if (meridiemFilter.HasValue)
        {
            query = query.Where(u => u.Meridiem == meridiemFilter.Value);
        }

        var records = await query
            .OrderBy(x => x.WeighTime)
            .ToListAsync();

        // 转换为增强的趋势点数据
        var trendPoints = new List<EnhancedWeightTrendPoint>();
        for (int i = 0; i < records.Count; i++)
        {
            var record = records[i];
            var point = new EnhancedWeightTrendPoint
            {
                Date = record.WeighTime,
                Weight = record.WeighKg,
                PeriodName = record.MeridiemInfo?.Name,
                Remark = record.Remark
            };

            // 计算与上一次同类型时段记录的变化量
            if (i > 0)
            {
                // 查找上一次同类型时段的记录
                var previousRecord = records.Take(i).LastOrDefault(r => r.Meridiem == record.Meridiem);
                if (previousRecord != null)
                {
                    point.ChangeFromPrevious = record.WeighKg - previousRecord.WeighKg;
                }
            }

            // 获取体脂率和其他身体指标
            if (record.BodyMetrics != null)
            {
                var bodyFatMetric = record.BodyMetrics.FirstOrDefault(b => b.MetricType == DictDataInitializer.MetricTypes.BodyFat);
                if (bodyFatMetric != null)
                {
                    point.BodyFat = bodyFatMetric.MetricValue;
                }

                var muscleMassMetric = record.BodyMetrics.FirstOrDefault(b => b.MetricType == DictDataInitializer.MetricTypes.MuscleMass);
                if (muscleMassMetric != null)
                {
                    point.MuscleMass = muscleMassMetric.MetricValue;
                }
            }

            trendPoints.Add(point);
        }

        restful.Code = CodeStatus.OK;
        restful.Data = trendPoints;
        return restful;
    }

    /// <summary>
    /// 获取当前数据快照
    /// </summary>
    /// <returns></returns>
    public async Task<RestfulResult<CurrentWeightSnapshot>> GetCurrentWeightSnapshotAsync()
    {
        var restful = new RestfulResult<CurrentWeightSnapshot>();

        // 获取最新体重记录
        var records = await _weighInfoRepository.AsQueryable()
            .Where(u => u.Creator == _currentUser.UserId)
            .OrderByDescending(x => x.WeighTime)
            .ToListAsync();
        var latestRecord = records.FirstOrDefault();

        if (latestRecord == null)
        {
            restful.Code = CodeStatus.OK;
            restful.Data = new CurrentWeightSnapshot();
            return restful;
        }

        var snapshot = new CurrentWeightSnapshot
        {
            CurrentWeight = latestRecord.WeighKg,
            CurrentWeightTime = latestRecord.WeighTime,
            PeriodName = latestRecord.MeridiemInfo?.Name
        };

        // 获取最新的身体指标
        if (latestRecord.BodyMetrics != null)
        {
            var bodyFatMetric = latestRecord.BodyMetrics.FirstOrDefault(b => b.MetricType == DictDataInitializer.MetricTypes.BodyFat);
            if (bodyFatMetric != null)
            {
                snapshot.BodyFat = bodyFatMetric.MetricValue;
            }

            var muscleMassMetric = latestRecord.BodyMetrics.FirstOrDefault(b => b.MetricType == DictDataInitializer.MetricTypes.MuscleMass);
            if (muscleMassMetric != null)
            {
                snapshot.MuscleMass = muscleMassMetric.MetricValue;
            }
        }

        restful.Code = CodeStatus.OK;
        restful.Data = snapshot;
        return restful;
    }

    /// <summary>
    /// 获取历史极值统计
    /// </summary>
    /// <returns></returns>
    public async Task<RestfulResult<WeightExtremes>> GetWeightExtremesAsync()
    {
        var restful = new RestfulResult<WeightExtremes>();

        var records = await _weighInfoRepository.AsQueryable()
            .Where(u => u.Creator == _currentUser.UserId)
            .OrderByDescending(x => x.WeighTime)
            .ToListAsync();

        if (records.Count == 0)
        {
            restful.Code = CodeStatus.OK;
            restful.Data = new WeightExtremes();
            return restful;
        }

        var extremes = new WeightExtremes
        {
            MaxWeight = records.Max(r => r.WeighKg),
            MinWeight = records.Min(r => r.WeighKg)
        };

        // 获取最高/最低体重的时间
        extremes.MaxWeightTime = records.FirstOrDefault(r => r.WeighKg == extremes.MaxWeight)?.WeighTime;
        extremes.MinWeightTime = records.FirstOrDefault(r => r.WeighKg == extremes.MinWeight)?.WeighTime;

        restful.Code = CodeStatus.OK;
        restful.Data = extremes;
        return restful;
    }

    /// <summary>
    /// 获取周期性变化统计
    /// </summary>
    /// <returns></returns>
    public async Task<RestfulResult<PeriodicChange>> GetPeriodicChangeAsync()
    {
        var restful = new RestfulResult<PeriodicChange>();

        // 获取所有记录
        var records = await _weighInfoRepository.AsQueryable()
            .Where(u => u.Creator == _currentUser.UserId)
            .OrderByDescending(x => x.WeighTime)
            .ToListAsync();

        if (records.Count < 2)
        {
            restful.Code = CodeStatus.OK;
            restful.Data = new PeriodicChange();
            return restful;
        }

        var currentWeight = records.First().WeighKg;
        var currentTime = records.First().WeighTime;

        // 查找7天前最近的记录
        var weekAgoDate = currentTime.AddDays(-7);
        var weekAgoRecord = records.FirstOrDefault(r => r.WeighTime <= weekAgoDate);

        // 查找30天前最近的记录
        var monthAgoDate = currentTime.AddDays(-30);
        var monthAgoRecord = records.FirstOrDefault(r => r.WeighTime <= monthAgoDate);

        var change = new PeriodicChange();
        if (weekAgoRecord != null)
        {
            change.WeeklyChange = currentWeight - weekAgoRecord.WeighKg;
            change.WeeklyChangeDate = weekAgoRecord.WeighTime;
        }

        if (monthAgoRecord != null)
        {
            change.MonthlyChange = currentWeight - monthAgoRecord.WeighKg;
            change.MonthlyChangeDate = monthAgoRecord.WeighTime;
        }

        restful.Code = CodeStatus.OK;
        restful.Data = change;
        return restful;
    }

    /// <summary>
    /// 获取累计变化与平均变化率
    /// </summary>
    /// <returns></returns>
    public async Task<RestfulResult<ChangeRate>> GetChangeRateAsync()
    {
        var restful = new RestfulResult<ChangeRate>();

        var records = await _weighInfoRepository.AsQueryable()
            .Where(u => u.Creator == _currentUser.UserId)
            .ToListAsync();

        if (records.Count < 2)
        {
            restful.Code = CodeStatus.OK;
            restful.Data = new ChangeRate();
            return restful;
        }

        // 获取最新和最早的记录
        var latestRecord = records.OrderByDescending(r => r.WeighTime).First();
        var earliestRecord = records.OrderBy(r => r.WeighTime).First();

        var totalChange = latestRecord.WeighKg - earliestRecord.WeighKg;
        var totalDays = (latestRecord.WeighTime - earliestRecord.WeighTime).TotalDays;

        var rate = new ChangeRate
        {
            TotalChange = totalChange,
            FirstWeight = earliestRecord.WeighKg,
            FirstWeightTime = earliestRecord.WeighTime,
            TotalDays = totalDays
        };

        // 计算平均变化率
        if (totalDays > 0)
        {
            rate.AvgWeeklyChange = totalChange / (totalDays / 7);
            rate.AvgMonthlyChange = totalChange / (totalDays / 30.4); // 按30.4天作为月均值
        }

        restful.Code = CodeStatus.OK;
        restful.Data = rate;
        return restful;
    }

    /// <summary>
    /// 根据时段获取体重统计
    /// </summary>
    /// <param name="meridiem">时段ID</param>
    /// <returns></returns>
    public async Task<RestfulResult<PeriodSpecificStat>> GetPeriodSpecificStatAsync(int meridiem)
    {
        var restful = new RestfulResult<PeriodSpecificStat>();

        var records = await _weighInfoRepository.AsQueryable()
            .Where(u => u.Creator == _currentUser.UserId && u.Meridiem == meridiem)
            .OrderByDescending(x => x.WeighTime)
            .ToListAsync();

        if (records.Count == 0)
        {
            restful.Code = CodeStatus.OK;
            restful.Data = new PeriodSpecificStat { PeriodId = meridiem };
            return restful;
        }

        var stat = new PeriodSpecificStat
        {
            PeriodId = meridiem,
            PeriodName = records.First().MeridiemInfo?.Name,
            CurrentWeight = records.First().WeighKg,
            CurrentWeightTime = records.First().WeighTime,
            MaxWeight = records.Max(r => r.WeighKg),
            MinWeight = records.Min(r => r.WeighKg),
            AverageWeight = records.Average(r => r.WeighKg),
            TotalRecords = records.Count
        };

        // 计算变化
        if (records.Count > 1)
        {
            stat.TotalChange = records.First().WeighKg - records.Last().WeighKg;
        }

        restful.Code = CodeStatus.OK;
        restful.Data = stat;
        return restful;
    }

    /// <summary>
    /// 获取扩展指标统计
    /// </summary>
    /// <param name="metricType">指标类型</param>
    /// <param name="days">查询天数</param>
    /// <returns></returns>
    public async Task<RestfulResult<MetricStat>> GetMetricStatAsync(string metricType, int days = 30)
    {
        var restful = new RestfulResult<MetricStat>();
        var startDate = DateTime.Now.AddDays(-days);

        // 查询指标数据
        var metrics = await _bodyMetricsRepository.AsQueryable()
            .Includes(b => b.WeightRecord)
            .Where(b => b.MetricType == metricType &&
                       b.WeightRecord != null &&
                       b.WeightRecord.Creator == _currentUser.UserId &&
                       b.WeightRecord.WeighTime >= startDate)
            .OrderBy(b => b.WeightRecord!.WeighTime)
            .ToListAsync();

        if (metrics.Count == 0)
        {
            restful.Code = CodeStatus.OK;
            restful.Data = new MetricStat { MetricType = metricType };
            return restful;
        }

        var stat = new MetricStat
        {
            MetricType = metricType,
            CurrentValue = metrics.Last().MetricValue,
            CurrentValueTime = metrics.Last().WeightRecord!.WeighTime,
            MaxValue = metrics.Max(m => m.MetricValue),
            MinValue = metrics.Min(m => m.MetricValue),
            AverageValue = metrics.Average(m => m.MetricValue),
            TotalRecords = metrics.Count
        };

        // 构建趋势数据
        stat.TrendData = metrics.Select(m => new MetricTrendPoint
        {
            Date = m.WeightRecord!.WeighTime,
            Value = m.MetricValue
        }).ToList();

        restful.Code = CodeStatus.OK;
        restful.Data = stat;
        return restful;
    }
}